CRUD分別代表的是:Create(建立、新增)、Read(讀取、查詢)、Update(更新、改正)、Delete(刪除),這4個動作就是在操作資料庫程式的時候最基本會用到的四項作業,中文一般稱作「增刪查改」。
CRUD對照到SQL語法和HTTP請求方法如下表格:
操作 | SQL | HTTP |
---|---|---|
Create | INSERT | POST/PUT |
Read | SELECT | GET |
Update | UPDATE | POST/PUT/PATCH |
Delete | DELETE | POST/DELETE |
關於更詳細的說明可以參考下列連結:
https://zh.wikipedia.org/zh-tw/%E5%A2%9E%E5%88%AA%E6%9F%A5%E6%94%B9
接著我們延續昨天使用Enitity Framework建立的資料庫內容,來示範如何達成CRUD各動作,同時也先在要實作網站專案之前,做個小小的統整練習。
我們先從目前最熟悉的Read開始,以使用者操作流程來說就是針對篩選的條件讀取資料,並顯示於畫面上。這部分我們練習過不少次了,參考步驟如下:
ShoppingController
內新增Read()
動作方法,目的是將所有會員資料顯示於清單,另外這邊刻意使用OrderByDescending
讓資料依照UserId
以降冪方式排序,Code如下: public ActionResult Read()
{
var db = new dbShoppingEntities();
var members = db.Member.OrderByDescending(m=>m.UserId).ToList();
return View(members);
}
接著新增Read()
的檢視頁面,這次我們試著使用快速的方式建立現成View,首先一樣先新增檢視,在加入時依照下圖選取「List」範本,並使用模型類別為「Member」,完成後按下「加入」。
※這邊有可能會發生EntityFramework相容問題,解決方式是將繁體中文套件解除安裝,可參考下圖處理。
移到檢視頁面會發現開發工具已經自動產生簡易的View,Code如下:
@model IEnumerable<DemoEntityFramework.Models.Member>
@{
ViewBag.Title = "Read";
}
<h2>Read</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.UserId)
</th>
<th>
@Html.DisplayNameFor(model => model.Password)
</th>
<th>
@Html.DisplayNameFor(model => model.UserName)
</th>
<th>
@Html.DisplayNameFor(model => model.Email)
</th>
<th>
@Html.DisplayNameFor(model => model.Address)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.UserId)
</td>
<td>
@Html.DisplayFor(modelItem => item.Password)
</td>
<td>
@Html.DisplayFor(modelItem => item.UserName)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.DisplayFor(modelItem => item.Address)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
@Html.ActionLink("Details", "Details", new { id=item.Id }) |
@Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
</table>
UserId
降冪排序。接著說明新增資料的方式,首先在Read的檢視會看到資料列表上方有個Create New
的連結,我們希望User按下這個連結後可以進入新增資料的頁面,另外從View的程式碼會看到ActionLink
預設的動作方法名稱為「Create」。
建立步驟如下:
Create()
方法,並新增對應的View,這次加入View時依照下圖選取「Create」範本,並使用模型類別為「Member」,完成後按下「加入」。 public ActionResult Create()
{
return View();
}
@model DemoEntityFramework.Models.Member
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Member</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.UserId, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.UserId, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.UserId, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Password, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Password, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.UserName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.UserName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.UserName, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Email, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Address, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Address, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Address, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
執行畫面如下,可以看到一個簡單的新增表單已經建立好了,左下方的Back to List
連結,預設會連到Index
,這邊我們將它改成Read
,以便可以回到原本查詢會員的頁面。
再來我們來處理在表單按下Submit鍵的動作,表單預設是使用HTTP POST請求 & 與檢視同名的Create()
動作方法,送出表單後會導回至Read頁面檢視新增後的內容,所以在Controller底下再新增如下Code:
[HttpPost]
public ActionResult Create(Member member)
{
var db = new dbShoppingEntities();
db.Member.Add(member);
db.SaveChanges();
return RedirectToAction("Read");
}
Add()
方法新增資料後,必須使用SaveChanges()
方法才會將變更的內容儲存,同理在做Edit與Delete的時候也一樣。在Read頁面每一筆資料後面都有Edit連結,我們希望點進去後可以修改資料內容,並且按下儲存後會回到Read頁面以檢視變更後結果。
首先看看Edit這個ActionLink是怎麼寫的,如下圖可以發現它會導向名為Edit的動作方法,且後面會帶一個路由值是該筆資料的Id。(路由的規範可以回頭看看DAY 3~)
在Member資料表內的Id欄位是屬於主索引鍵,主索引鍵必須是唯一值且不可為NULL,一張資料表內只會有一個主索引鍵,概念可以想成是不會重複的流水編號,因此通常用作為網址的路由值。
當我們將滑鼠移至Edit連結的上方,可以看到瀏覽器下方顯示的網址為https://localhostXXXXX/Shoppong/Edit/{id}
,等同於https://localhostXXXXX/Shoppong/Edit?id={id}
,是否有印象在DAY 3時我們也看過類似的範例呢?
因此作法如下:
Edit()
動作方法,並將參數id
放入其中,透過LINQ查詢Member
物件中符合該唯一id的資料,將它當作model傳入View使用,參考下方Code: public ActionResult Edit(int id)
{
var db = new dbShoppingEntities();
var member = db.Member.Where(m => m.Id == id).FirstOrDefault();
//也可寫成下面
//var member = db.Member.FirstOrDefault(m => m.Id == id);
return View(member);
}
接著撰寫View的部分,加入View時依照下圖選取「Edit」範本,並使用模型類別為「Member」,完成後按下「加入」。
產生的Code如下,一樣將左下方的Back to List
連結改成Read
,以便可以回到原本的頁面。
@model DemoEntityFramework.Models.Member
@{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Member</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.Id)
<div class="form-group">
@Html.LabelFor(model => model.UserId, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.UserId, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.UserId, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Password, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Password, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.UserName, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.UserName, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.UserName, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Email, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Address, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Address, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Address, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Read")
</div>
將頁面執行起來後畫面如下,可以看到呈現方式一樣是個表單,但透過將model傳入view,原本的資料內容會被帶進來。
再來就是按下表單送出的部分啦~同樣是要寫個POST方法,並導回Read頁面。修改的原理也很好懂,利用Id
條件判斷取得資料庫內該筆資料,然後將修改送出後的物件屬性一一賦值回該筆資料,最後記得使用SaveChanges()
儲存變更,Code如下:
[HttpPost]
public ActionResult Edit(Member member)
{
var db = new dbShoppingEntities();
var memberData = db.Member.Where(m => m.Id == member.Id).FirstOrDefault();
memberData.UserId = member.UserId;
memberData.UserName = member.UserName;
memberData.Password = member.Password;
memberData.Email = member.Email;
memberData.Address = member.Address;
db.SaveChanges();
return RedirectToAction("Read");
}
刪除單筆資料的道理和Edit做法很像,差別是在於取得資料後就直接把該筆資料移除了。另外刪除前我們希望先顯示要刪除的資料內容,可以讓User有個確認和反悔的機會。
因此一樣先建立Delete()
動作方法,加入id參數。
public ActionResult Delete(int id)
{
var db = new dbShoppingEntities();
var member = db.Member.Where(m => m.Id == id).FirstOrDefault();
return View(member);
}
接著新增View,範本改選擇「Delete」。
View Code如下,一樣將左下方的Back to List
連結改成Read
,以便可以回到原本的頁面。
@model DemoEntityFramework.Models.Member
@{
ViewBag.Title = "Delete";
}
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Member</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.UserId)
</dt>
<dd>
@Html.DisplayFor(model => model.UserId)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Password)
</dt>
<dd>
@Html.DisplayFor(model => model.Password)
</dd>
<dt>
@Html.DisplayNameFor(model => model.UserName)
</dt>
<dd>
@Html.DisplayFor(model => model.UserName)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Email)
</dt>
<dd>
@Html.DisplayFor(model => model.Email)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Address)
</dt>
<dd>
@Html.DisplayFor(model => model.Address)
</dd>
</dl>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-actions no-color">
<input type="submit" value="Delete" class="btn btn-default" /> |
@Html.ActionLink("Back to List", "Read")
</div>
}
</div>
View執行畫面如下:
最後就是刪除的POST方法,使用Remove()
來移除選擇的資料,並執行SaveChange()
,Code如下:
[HttpPost]
public ActionResult Delete(Member member)
{
var db = new dbShoppingEntities();
var memberData = db.Member.Where(m => m.Id == member.Id).FirstOrDefault();
db.Member.Remove(memberData);
db.SaveChanges();
return RedirectToAction("Read");
}
完成後就可以實際來測試看看是否能確實刪除資料囉~
今天介紹了基本CRUD方法,利用Entity Framework簡單操作資料庫內容,並且透過內建的範本快速建立檢視頁面。前面這10天相信大家對MVC互動的方式愈來愈熟悉了,接下來的幾天就要來實作一個小型的網站專案囉~那就明天見啦!
※小弟不才,在軟體的世界還只是個小菜雞,如果內容有任何謬誤或問題,還請各位大神前輩們多多批評指教~歡迎下方留言討論^^